import {
    AmbientLight,
    AxesHelper,
    BoxBufferGeometry,
    GridHelper, Matrix4,
    Mesh,
    MeshStandardMaterial,
    MOUSE, Object3D,
    PerspectiveCamera, PointLight,
    Scene,
    Vector3,
    WebGLRenderer,
    Raycaster, Vector2, Material, Group
} from "three";
import Stats from "three/examples/jsm/libs/stats.module";
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";
import {TransformControls} from "three/examples/jsm/controls/TransformControls";
import {EventManage} from '../source/eventManage'

export class TEngine {
    private dom: HTMLElement;
    private renderer: WebGLRenderer;
    private scene: Scene;
    private camera: PerspectiveCamera;
    private transformControls: TransformControls;
    private eventManage: EventManage;

    constructor(dom: HTMLElement,) {
        this.dom = dom;

        //    绘制相机
        const camera = new PerspectiveCamera(60, dom.offsetWidth / dom.offsetHeight, 0.1, 1000);
        //设置相机的指向
        camera.lookAt(new Vector3(0, 0, 0))
        // 设置相机位置
        camera.position.set(200, 300, 500)
        //设置相机的正向拍摄
        camera.up = new Vector3(0, 1, 0)

        // 绘制场景
        const scene = new Scene();

        //绘制渲染器, 设置尺寸, 将渲染器添加到dom上
        const renderer = new WebGLRenderer({
            antialias: true, //添加抗锯齿
        });
        renderer.setSize(dom.offsetWidth, dom.offsetHeight, true);

        //开启阴影渲染
        renderer.shadowMap.enabled = true;

        //添加监视器
        const stats = Stats();
        const statsDom = stats.domElement;
        statsDom.style.position = 'fixed';
        statsDom.style.top = '0';
        statsDom.style.right = '5px';
        statsDom.style.left = 'unset'

        //添加轨道控制器, 第一个参数为: 将要被控制的相机
        const orbitControls: OrbitControls = new OrbitControls(camera, renderer.domElement)
        //开启相机自动选择
        // orbitControls.autoRotate = true
        // orbitControls.enabled = true
        //拖拉的缓存效果开启
        // orbitControls.enableDamping = true
        /*设置轨道控制器的鼠标按键功能, 可以重置鼠标键
            使用变换控制器， 左键需要置空才方便使用
         */
        orbitControls.mouseButtons = {
            LEFT: null as unknown as MOUSE,
            MIDDLE: MOUSE.ROTATE,
            RIGHT: MOUSE.PAN
        }


        //创建变换控制器, 将变换控制器添加到场景中
        const transformControls: TransformControls = new TransformControls(camera, renderer.domElement)
        scene.add(transformControls)


        //添加事件监听
        const eventManage = new EventManage({
            dom: renderer.domElement,
            camera: camera,
            scene: scene
        })


        let cacheObject: Mesh | null = null;
        eventManage.addEventListener('mousemove', e => {
            const {intersections} = e;
            if(intersections.length) {
                const object = intersections[0].object;

                if(object === cacheObject) {
                    return
                }else {
                    // 缓存物体和当前物体不一致
                    // 1.从空白区域移入物体中
                    // 2.从一个物体移入另一个物体中
                    if(cacheObject) {
                        (cacheObject.material as MeshStandardMaterial).color.multiplyScalar(0.5)
                    }

                    if(object.material) {
                        object.material.color.multiplyScalar(2)
                        cacheObject = object
                    }
                }
            } else {
                if (cacheObject) {
                    (cacheObject.material as MeshStandardMaterial).color.multiplyScalar(0.5)
                }
                cacheObject = null;
            }
        })

        /* 每次点击物体 变换控制器 拾取到物体操作过程中, 如果该物体在三维空间的后面还有物体, 当操作完成物体变换后, 又触发click, 而拾取到了后面的物体
            解决方法: 定义一个变量transing, 用于存储当前变换控制器操作, 当停止操作物体的时候,不触发click拾取
        * */
        let transing = false;
        transformControls.addEventListener('mouseDown', e => {
            transing = true;
        })

        eventManage.addEventListener('click', e => {
            //变换控制器拖动结束
            if(transing) {
                transing = false;
                return false;
            }
            const {intersections} = e;

            if(intersections.length) {
                //找到射线相交 距离最近的第一个物体，然后绑定在变换控制器上
                const object = intersections[0].object as Object3D;
                if(object.type === 'TransformControlsPlane') {
                    transformControls.detach();
                    //移除变换控制器
                    scene.remove(transformControls)
                }else {
                    scene.add(transformControls)
                    transformControls.attach(object.parent instanceof Group ? object.parent: object)
                }
            }
        })


        //监听键盘事件, 切换变换控制器的模式
        document.addEventListener('keyup', e => {
            switch (e.key) {
                case 'e':
                    transformControls.mode = 'scale';
                    return false;
                case 'r':
                    transformControls.mode = 'rotate';
                    return false;
                case 't':
                    transformControls.mode = 'translate';
                    return false;
            }
        })

        const fun = () => {
            // box.rotation.y += 0.002;
            //更新轨道控制器, 在render执行之前
            orbitControls.update()

            //将场景和相机添加到渲染器中
            renderer.render(scene, camera)
            stats.update()
            requestAnimationFrame(fun);
        }
        fun()


        this.dom.appendChild(renderer.domElement);
        this.dom.appendChild(statsDom)

        //赋值到this上
        this.camera = camera;
        this.scene = scene;
        this.renderer = renderer;
        this.transformControls = transformControls;
        this.eventManage = eventManage;
    }

    addObject(...args: Object3D[]) {
        this.scene.add(...args)
    }
}